import * as THREE from 'three';
import { Octree } from 'three/examples/jsm/math/Octree.js';
import { Capsule } from 'three/examples/jsm/math/Capsule.js';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls';

export default class FirstPersonControls {
    constructor(scene, camera, renderer, container, models = []) {
        this.scene = scene;
        this.camera = camera;
        this.renderer = renderer;
        this.container = container;

        // 控制状态
        this.isActive = false;
        this.keyState = {
            KeyW: false,
            KeyA: false,
            KeyS: false,
            KeyD: false,
            Space: false,
            ShiftLeft: false,
            KeyE: false,
            KeyF: false
        };
        this.canJump = false;
        this.isCrouching = false;
        this.isClimbing = false;
        this.isGrabbing = false;
        
        // 调整后的运动参数（更高更快）
        this.moveSpeed = 135;      // 基础移动速度
        this.runSpeed = 45;       // 跑步速度
        this.jumpForce = 20;      // 跳跃力量
        this.crouchHeight = 1.5;  // 蹲下高度
        this.climbSpeed = 15;       // 攀爬速度
        this.grabDistance = 2.5;   // 抓取距离
        this.grabStrength = 40;    // 抓取力量

        // 初始化八叉树
        this.worldOctree = new Octree();
        
        // 调整后的玩家碰撞体（更高）
        this.playerCollider = new Capsule(
            new THREE.Vector3(0, 0.5, 0),    // 起点提高
            new THREE.Vector3(0, 6.0, 0),    // 终点提高
            0.2                            // 半径增大
        );
        
        // 存储原始参数
        this.originalHeight = 1.8;  // 原始高度
        this.originalRadius = 0.2;  // 原始半径

        // 控制器
        this.controls = new PointerLockControls(camera, container);

        // 事件监听器
        this.eventListeners = [];

        // 抓取的物体
        this.grabbedObject = null;
        this.grabConstraint = null;

        // 初始化
        this.initCollisionBodies(models);
        this.setupEventListeners();
    }

    initCollisionBodies(models) {
        // 遍历所有模型创建碰撞体
        const traverseAndAddColliders = (object) => {
            if (object.isMesh) {
                object.updateMatrixWorld();
                
                const box = new THREE.Box3().setFromObject(object);
                const size = box.getSize(new THREE.Vector3());
                
                if (size.length() < 0.2) return;
                
                // 添加到八叉树
                this.worldOctree.fromGraphNode(object);
            }
            
            if (object.children && object.children.length > 0) {
                object.children.forEach(child => traverseAndAddColliders(child));
            }
        };
        
        models.forEach(model => traverseAndAddColliders(model));
    }

    setupEventListeners() {
        // 键盘控制
        const onKeyDown = (event) => {
            if (event.code in this.keyState) {
                this.keyState[event.code] = true;
                
                // 抓取/释放物体
                if (event.code === 'KeyE' && !this.isGrabbing) {
                    this.tryGrabObject();
                } else if (event.code === 'KeyE' && this.isGrabbing) {
                    this.releaseObject();
                }
                
                // 攀爬/取消攀爬
                if (event.code === 'KeyF' && !this.isClimbing) {
                    this.tryStartClimbing();
                } else if (event.code === 'KeyF' && this.isClimbing) {
                    this.stopClimbing();
                }
            }
            
            // 蹲下切换
            if (event.code === 'KeyC') {
                this.toggleCrouch();
            }
        };

        const onKeyUp = (event) => {
            if (event.code in this.keyState) {
                this.keyState[event.code] = false;
            }
        };

        document.addEventListener('keydown', onKeyDown);
        document.addEventListener('keyup', onKeyUp);

        this.eventListeners.push(
            { element: document, handler: onKeyDown, type: 'keydown' },
            { element: document, handler: onKeyUp, type: 'keyup' }
        );

        // 点击锁定控制
        const onClick = () => {
            if (this.isActive) {
                this.controls.lock();
            }
        };

        this.container.addEventListener('click', onClick);
        this.eventListeners.push({ element: this.container, handler: onClick, type: 'click' });
    }

    tryGrabObject() {
        const direction = new THREE.Vector3();
        this.camera.getWorldDirection(direction);
        
        const ray = new THREE.Raycaster(
            this.camera.position,
            direction,
            0,
            this.grabDistance
        );
        
        const intersects = ray.intersectObjects(this.scene.children, true);
        
        if (intersects.length > 0) {
            const object = intersects[0].object;
            this.grabbedObject = object;
            this.isGrabbing = true;
            
            // 创建抓取约束
            this.grabConstraint = {
                object: object,
                offset: new THREE.Vector3().subVectors(
                    this.camera.position,
                    object.position
                )
            };
        }
    }

    releaseObject() {
        this.grabbedObject = null;
        this.grabConstraint = null;
        this.isGrabbing = false;
    }

    tryStartClimbing() {
        const direction = new THREE.Vector3();
        this.camera.getWorldDirection(direction);
        
        const ray = new THREE.Raycaster(
            this.camera.position,
            direction,
            0,
            1.5
        );
        
        const intersects = ray.intersectObjects(this.scene.children, true);
        
        if (intersects.length > 0 && 
            (intersects[0].object.name.includes('climbable') || 
             intersects[0].object.name.includes('ladder'))) {
            this.isClimbing = true;
            this.playerVelocity = new THREE.Vector3();
        }
    }

    stopClimbing() {
        this.isClimbing = false;
    }

    toggleCrouch() {
        if (this.isClimbing) return;
        
        this.isCrouching = !this.isCrouching;
        
        if (this.isCrouching) {
            this.playerCollider.end.y = this.playerCollider.start.y + this.crouchHeight - this.originalRadius * 2;
            this.moveSpeed = 25; // 蹲下移动速度
        } else {
            this.playerCollider.end.y = this.playerCollider.start.y + this.originalHeight - this.originalRadius * 2;
            this.moveSpeed = this.keyState.ShiftLeft ? this.runSpeed : 35;
        }
    }

    activate() {
        if (this.isActive) return;

        this.isActive = true;
        this.scene.add(this.controls.getObject());
        this.controls.lock();

        // 设置初始碰撞体位置（更高）
        this.playerCollider.start.set(
            this.camera.position.x,
            this.camera.position.y - 0.5,  // 调整高度
            this.camera.position.z
        );
        this.playerCollider.end.set(
            this.camera.position.x,
            this.camera.position.y + 1.5,   // 调整高度
            this.camera.position.z
        );
        this.playerVelocity = new THREE.Vector3();
    }

    deactivate() {
        if (!this.isActive) return;

        this.isActive = false;
        this.controls.unlock();
        this.scene.remove(this.controls.getObject());

        if (this.isGrabbing) {
            this.releaseObject();
        }
        
        if (this.isClimbing) {
            this.stopClimbing();
        }

        this.camera.position.copy(
            new THREE.Vector3(
                this.playerCollider.end.x,
                this.playerCollider.end.y + (this.isCrouching ? 0.5 : 1.5),  // 调整高度
                this.playerCollider.end.z
            )
        );
    }

    update(delta) {
        if (!this.isActive) return;
    
        // 同步玩家位置（调整高度）
        this.camera.position.copy(
            new THREE.Vector3(
                this.playerCollider.end.x,
                this.playerCollider.end.y - (this.isCrouching ? 0.5 : 1.5),  // 调整高度
                this.playerCollider.end.z
            )
        );
        
        this.controls.update();
        
        // 玩家移动控制
        if (this.controls.isLocked) {
            if (this.isClimbing) {
                this.handleClimbingMovement(delta);
            } else if (this.isGrabbing) {
                this.handleGrabbingMovement(delta);
            } else {
                this.handleNormalMovement(delta);
            }
        }
    
        // 碰撞检测和响应
        this.updatePlayer(delta);
    }

    updatePlayer(delta) {
        const damping = Math.exp(-4 * delta) - 1;
        
        if (!this.isClimbing) {
            this.playerVelocity.addScaledVector(this.playerVelocity, damping);
        }
        
        // 重力
        if (!this.isClimbing) {
            this.playerVelocity.y -= 15 * delta;
        }
        
        const deltaPosition = this.playerVelocity.clone().multiplyScalar(delta);
        this.playerCollider.translate(deltaPosition);
        
        // 碰撞检测
        const result = this.worldOctree.capsuleIntersect(this.playerCollider);
        
        if (result) {
            this.canJump = result.normal.y > 0;
            
            // 处理斜坡
            if (result.normal.y < 1) {
                const slopeFactor = result.normal.y;
                this.playerVelocity.x *= slopeFactor;
                this.playerVelocity.z *= slopeFactor;
            }
            
            // 响应碰撞
            this.playerCollider.translate(result.normal.multiplyScalar(result.depth));
        }
        
        // 更新抓取物体的位置
        if (this.isGrabbing && this.grabConstraint) {
            const direction = new THREE.Vector3();
            this.camera.getWorldDirection(direction);
            
            this.grabConstraint.object.position.copy(
                new THREE.Vector3().subVectors(
                    this.camera.position,
                    this.grabConstraint.offset
                )
            );
        }
    }

    handleClimbingMovement(delta) {
        const direction = new THREE.Vector3();
        this.camera.getWorldDirection(direction);
        
        const moveDirection = new THREE.Vector3();
        
        if (this.keyState.KeyW) {
            moveDirection.y += this.climbSpeed * delta;
        }
        if (this.keyState.KeyS) {
            moveDirection.y -= this.climbSpeed * delta;
        }
        
        // 攀爬时允许更大的水平移动
        if (this.keyState.KeyA) {
            moveDirection.x -= this.climbSpeed * 0.5 * delta;
        }
        if (this.keyState.KeyD) {
            moveDirection.x += this.climbSpeed * 0.5 * delta;
        }
        
        this.playerVelocity.copy(moveDirection);
        this.canJump = false;
    }

    handleGrabbingMovement(delta) {
        const currentSpeed = this.keyState.ShiftLeft ? this.runSpeed * 0.7 : this.moveSpeed * 0.7;
        
        const direction = new THREE.Vector3();
        this.camera.getWorldDirection(direction);
        direction.y = 0;
        direction.normalize();
        
        const sideDirection = new THREE.Vector3();
        sideDirection.crossVectors(new THREE.Vector3(0, 1, 0), direction);
        sideDirection.normalize();

        const moveDirection = new THREE.Vector3();
        
        if (this.keyState.KeyW) {
            moveDirection.addScaledVector(direction, currentSpeed * delta);
        }
        if (this.keyState.KeyS) {
            moveDirection.addScaledVector(direction, -currentSpeed * delta);
        }
        if (this.keyState.KeyA) {
            moveDirection.addScaledVector(sideDirection, currentSpeed * delta);
        }
        if (this.keyState.KeyD) {
            moveDirection.addScaledVector(sideDirection, -currentSpeed * delta);
        }
        
        moveDirection.y = this.playerVelocity.y;
        this.playerVelocity.copy(moveDirection);
        
        if (this.keyState.Space && this.canJump) {
            this.playerVelocity.y = this.jumpForce * 0.8;
            this.canJump = false;
        }
    }

    handleNormalMovement(delta) {
        const speedMultiplier = this.isCrouching ? 0.9 : 1.3;
        const currentSpeed = this.keyState.ShiftLeft && !this.isCrouching ? this.runSpeed : this.moveSpeed;
        
        const direction = new THREE.Vector3();
        this.camera.getWorldDirection(direction);
        direction.y = 0;
        direction.normalize();
        
        const sideDirection = new THREE.Vector3();
        sideDirection.crossVectors(new THREE.Vector3(0, 1, 0), direction);
        sideDirection.normalize();

        const moveDirection = new THREE.Vector3();
        
        if (this.keyState.KeyW) {
            moveDirection.addScaledVector(direction, currentSpeed * delta * speedMultiplier);
        }
        if (this.keyState.KeyS) {
            moveDirection.addScaledVector(direction, -currentSpeed * delta * speedMultiplier);
        }
        if (this.keyState.KeyA) {
            moveDirection.addScaledVector(sideDirection, currentSpeed * delta * speedMultiplier);
        }
        if (this.keyState.KeyD) {
            moveDirection.addScaledVector(sideDirection, -currentSpeed * delta * speedMultiplier);
        }
        
        moveDirection.y = this.playerVelocity.y;
        this.playerVelocity.copy(moveDirection);

        if (this.keyState.Space && this.canJump && !this.isCrouching) {
            this.playerVelocity.y = this.jumpForce;
            this.canJump = false;
        }
    }

    dispose() {
        this.deactivate();

        this.eventListeners.forEach(({ element, handler, type }) => {
            element.removeEventListener(type, handler);
        });

        this.controls.dispose();
    }
}